﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Validity.Rules;

namespace Validity.Test.Rules
{
  [TestClass]
  public class RuleTest
  {
    [TestMethod]
    public void TestIsViolatedByArgSameAsArgProvided()
    {
      ObjectStub expectedObj = new ObjectStub();
      Object expectedValue = new Object();

      var rule = new Rule<ObjectStub, Object>(
        (obj, val) => 
        {
          Assert.AreSame(expectedObj, obj);
          Assert.AreSame(expectedValue, val);
          return true;
        },
        (obj, val) => "Message"
      );
      
      rule.IsViolatedBy(expectedObj, expectedValue);
    }

    [TestMethod]
    public void TestIsViolatedByReturnsFalseWhenConstraintEvaluatesTrue()
    {
      var rule = new Rule<ObjectStub, Object>((obj, val) => true, (obj, val) => "Message");

      Assert.IsFalse(rule.IsViolatedBy(new ObjectStub(), new Object()));
    }

    [TestMethod]
    public void TestIsViolatedByReturnsTrueWhenConstraintEvaluatesFalse()
    {
      var rule = new Rule<ObjectStub, Object>((obj, val) => true, (obj, val) => "Message");

      Assert.IsFalse(rule.IsViolatedBy(new ObjectStub(), new Object()));
    }

    [TestMethod]
    public void TestGetRuleViolationArgsSameAsArgsProvided()
    {
      ObjectStub expectedObj = new ObjectStub();
      Object expectedVal = new Object();

      var rule = new Rule<ObjectStub, Object>(
        (obj, val) => true,
        (obj, val) =>
        {
          Assert.AreSame(expectedObj, obj);
          Assert.AreSame(expectedVal, val);

          return "Message";
        }
      );

      rule.GetRuleViolation(expectedObj, expectedVal);
    }

    [TestMethod]
    public void TestGetRuleViolationReturnsDefaultOnNullMessageFactoryResult()
    {
      var rule = new Rule<ObjectStub, Object>((obj, val) => true, (obj, val) => null);

      Assert.AreEqual("Value is invalid", rule.GetRuleViolation(new ObjectStub(), new Object()));
    }

    [TestMethod]
    public void TestGetRuleViolationReturnsNonNullMessageFactoryResult()
    {
      var rule = new Rule<ObjectStub, Object>((obj, val) => true, (obj, val) => "Message");

      Assert.AreEqual("Message", rule.GetRuleViolation(new ObjectStub(), new Object()));
    }
  }
}
